package deepr.lib;

import deepr.anno.LifeCycle;
import deepr.exception.LifeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.util.Assert;

import java.lang.reflect.Array;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
public class CastLib {

  public static DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
  public static DateFormat fdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  public static <K, V> Map<K, V> castMap(Object obj, Class<K> tClass, Class<V> vClass) throws LifeException {
    HashMap<K, V> result = new HashMap<>();
    if (obj instanceof Map<?, ?>) {
      Map<?, ?> map = (Map<?, ?>) (obj);
      for (Map.Entry<?, ?> entry : map.entrySet()) {
        result.put(tClass.cast(entry.getKey()), vClass.cast(entry.getValue()));
      }
      return result;
    }
    throw new LifeException("CastList Error", LifeCycle.CAST, obj);
  }

  public static <T> String[] castArrayString(Object obj) throws LifeException {
    if (obj.getClass().isArray()) {
      int length = Array.getLength(obj);
      String[] os = new String[length];
      for (int i = 0; i < os.length; i++) {
        os[i] = (String) Array.get(obj, i);
      }
      return os;
    }
    throw new LifeException("CastList Error", LifeCycle.CAST, obj);
  }

  public static <T> List<T> castList(Object obj, Class<T> clazz) throws LifeException {
    List<T> result = new ArrayList<T>();
    int count = 0;
    if (obj instanceof List<?>) {
      for (Object o : (List<?>) obj) {
        result.add(clazz.cast(o));
        count++;
        if (count > 5) {
          throw new LifeException("List Too Long", LifeCycle.CAST, obj);
        }
      }
      return result;
    }
    throw new LifeException("CastList Error", LifeCycle.CAST, obj);
  }

  public static Object toLong(String key, Object value) {
    if (value instanceof String) {
      return Long.parseLong((String) value);
    }
    if (value instanceof Integer) {
      return (Long) value;
    }
    if (value instanceof Float || value instanceof Long) {
      return (Long) value;
    }
    if (value.getClass().isArray()) {
      Object[] a = (Object[]) value;
      for (int i = 0; i < a.length; i++) {
        a[i] = toLong(key, a[i]);
      }
      return a;
    }
    Assert.isTrue(false, key + " value can't to int");
    return null;
  }

  public static Object toInteger(String key, Object value) {
    if (value instanceof String) {
      return Integer.parseInt((String) value);
    }
    if (value instanceof Integer) {
      return value;
    }
    if (value instanceof Float || value instanceof Long) {
      return (Integer) value;
    }
    if (value.getClass().isArray()) {
      Object[] a = (Object[]) value;
      for (int i = 0; i < a.length; i++) {
        a[i] = toInteger(key, a[i]);
      }
      return a;
    }
    Assert.isTrue(false, key + " value can't to int");
    return null;
  }

  public static Object toDate(String key, Object value) throws ParseException {
    if (value instanceof String) {
      return fmt.parse((String) value);
    }
    if (value instanceof Date) {
      return value;
    }
    if (value.getClass().isArray()) {
      Object[] a = (Object[]) value;
      for (int i = 0; i < a.length; i++) {
        a[i] = toDate(key, a[i]);
      }
      return a;
    }
    Assert.isTrue(false, key + " value can't to date");
    return null;
  }

  public static Object toDateTime(String key, Object value) throws ParseException {
    if (value instanceof String) {
      return fdt.parse((String) value);
    }
    if (value instanceof LocalDateTime) {
      return value;
    }
    if (value.getClass().isArray()) {
      Object[] a = (Object[]) value;
      for (int i = 0; i < a.length; i++) {
        a[i] = toDateTime(key, a[i]);
      }
      return a;
    }
    Assert.isTrue(false, key + " value can't to datetime");
    return null;
  }

}
